package ru.ifmo.rybakov.muclumon.analysis;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ru.ifmo.rybakov.muclumon.Properties;
import ru.ifmo.rybakov.muclumon.Property;
import ru.ifmo.rybakov.muclumon.PropertyManager;
import ru.ifmo.rybakov.muclumon.StringValue;
import ru.ifmo.rybakov.muclumon.Task;

public class TaskMethodClusteringAlgorithm {
	
	public ICluster[] run(Task[] tasks) {
		TaskCluster unknown = null;
		Map<String, TaskCluster> byApp = new HashMap<String, TaskCluster>();
		Map<String, Map<String, TaskCluster>> byAppAndMethod = new HashMap<String, Map<String,TaskCluster>>();
		
		Property applicationProperty = PropertyManager.get(Properties.TASK_APPLICATION);
		Property methodProperty = PropertyManager.get(Properties.TASK_METHOD);
		
		for (Task task : tasks) {
			StringValue appName = (StringValue) task.getSingleValue(applicationProperty);
			if (appName == null) {
				if (unknown == null) {
					unknown = new TaskCluster(task);
				} else { // merge
					unknown = (TaskCluster) unknown.merge(new TaskCluster(task));
				}
			} else {
				StringValue methodName = (StringValue) task.getSingleValue(methodProperty);
				if (methodName == null) {
					if (byApp.containsKey(appName.getValue())) { // merge
						byApp.put(appName.getValue(), (TaskCluster) byApp.get(appName.getValue()).merge(new TaskCluster(task)));
					} else {
						byApp.put(appName.getValue(), new TaskCluster(task));
					}
				} else {
					Map<String, TaskCluster> clustersByApp = byAppAndMethod.get(appName.getValue());
					if (clustersByApp == null) {
						clustersByApp = new HashMap<String, TaskCluster>();
						clustersByApp.put(methodName.getValue(), new TaskCluster(task));
						byAppAndMethod.put(appName.getValue(), clustersByApp);
					} else {
						if (clustersByApp.containsKey(methodName.getValue())) { // merge
							clustersByApp.put(methodName.getValue(), (TaskCluster) clustersByApp.get(methodName.getValue()).merge(new TaskCluster(task)));
						} else {
							clustersByApp.put(methodName.getValue(), new TaskCluster(task));
						}
					}
				}
			}
		}
		
		// output
		// ICluster[] result = new TaskCluster[clusterCount];
		List<TaskCluster> result = new ArrayList<TaskCluster>();
		if (unknown != null) {
			result.add(unknown);
		}
		result.addAll(byApp.values());
		for (Map<String, TaskCluster> byMethod : byAppAndMethod.values()) {
			result.addAll(byMethod.values());
		}
		ICluster[] resultArray = new ICluster[result.size()];
		result.toArray(resultArray);
		return resultArray;
	}
}
